﻿using System.Collections.Generic;
using System.Runtime.CompilerServices;
using CthulhuDomain.Services;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using CthulhuDomain.Strategies;

namespace CthulhuDomain.GameEntities
{
  public abstract class DomainEntity : IPower
  {
    public enum eDirection
    {
      None = 0,
      Up = 1,
      Down = 2
    }

    protected IVector2 pos;
    public abstract int Height { get; set; }
    public abstract int Width { get; set; }
    public abstract float Speed { get; set; }
    public abstract IVector2 Position { get; set; }
    public virtual int LifePoint { get; set; }
    public virtual int Amount {
      get { return Score.Amount; }
    }

    #region Animation

    public virtual int FrameColumns { get; set; }
    public IGraphicResource Texture { get; set; }
    public bool IsAnimated { get { return FrameColumns > 0; } }
    int currentFrame;
    public int CurrentFrame {
      get {
        if (currentFrame >= FrameColumns)
          currentFrame = 0;
        return currentFrame;
      }
      set {
        currentFrame = value;
      }
    }
    protected int timeSinceLastFrame;
    protected virtual int Mpf { get { return 60; } }

    #endregion

    public MovementStrategy MovementStrategy { get; set; }
    public Score Score { get; set; }
    public abstract int Damage { get; }

    #region Move

    public void Move(IRectangle context) {
      MovementStrategy.Move(context);
    }

    public void Move(IRectangle context, Keys[] keys) {
      MovementStrategy.Move(context, keys);
    }

    public void Move(IRectangle context, IGameTime time) {
      MovementStrategy.Move(context, time);
    }

    #endregion

    #region Update

    public virtual void Update(IGameTime gameTime) {
    }

    public virtual void Update(IRectangle context, IGameTime time) {
    }

    public virtual void Update(IRectangle context, Keys[] keys) {
    }

    #endregion

    #region Draw

    public virtual void Draw(ISpriteBatch spriteBatch) {
      Draw(spriteBatch, new ColorAdapter(Color.White));
    }

    public virtual void Draw(ISpriteBatch spriteBatch, IColor color) {
      spriteBatch.Draw(Texture,
                       Position,
                       new RectangleAdapter(CurrentFrame * Width, 0, Width, Height),
                       color);
    }

    public virtual void Draw(ISpriteBatch spriteBatch, IColor color, float scale, int zIndex) {
      spriteBatch.Draw(Texture, Position, new RectangleAdapter(CurrentFrame * Width, 0, Width, Height),
                       color, new Vector2Adapter(scale, scale), zIndex);
    }

    #endregion

    public DomainEntity ProtoTypeChild { get; set; }
    public List<DomainEntity> Shoots;
    public List<DomainEntity> PowerUps;
    private float _bulletSpeed = 2f;

    public float BulletSpeed {
      get { return _bulletSpeed; }
      set { _bulletSpeed = value; }
    }

    public int ShootsCount {
      get { return Shoots != null ? Shoots.Count : 0; }
    }
    public int PowerUpsCount {
      get { return PowerUps != null ? PowerUps.Count : 0; }
    }

    internal virtual void AddShoot() { }
    internal virtual void AddPowerUp() { }

    protected void RemoveEntityOutOfContext() {
      Shoots.RemoveAll(x => x != null && x.Position.Y <= 0);
      Shoots.TrimExcess();
      if (PowerUps == null) return;
      PowerUps.RemoveAll(x => x != null && x.Position.Y <= 0);
      PowerUps.TrimExcess();
    }

    public DomainEntity GetShoot(int index) {
      return Shoots[index];
    }

    public DomainEntity GetPowerUp(int index) {
      return PowerUps[index];
    }

    internal bool Intersect(DomainEntity tEntity) {
      var bound = new RectangleAdapter((int)Position.X, (int)Position.Y, Width, Height);
      var tbound = new RectangleAdapter((int)tEntity.Position.X, (int)tEntity.Position.Y, tEntity.Width, tEntity.Height);

      return bound.Adaptee.Intersects(tbound.Adaptee);
    }

    internal void SetShoot(int index, DomainEntity domainEntity) {
      Shoots[index] = domainEntity;
    }

    void SetPowerUp(int index, DomainEntity domainEntity) {
      PowerUps[index] = domainEntity;
    }

    public void AddPowerUp(DomainEntity domainEntity) {
      CollisionManager.AddPowerUp(domainEntity);
    }

    protected IColor ColorByLifePoint(int lifePoint) {
      #region

      //var p = lifePoint != 0 ? lifePoint : 1;
      //var pp = 10 * p <= 256 ? 256 - 50 * p : 256;
      //var ppp = 20 * p <= 256 ? 256 - 50 * p : 256;
      //var pppp = 256 - 256 / p;

      //int r = pppp, g = ppp, b = pp;
      //var color = new Color(r, g, b);

      #endregion

      Color color;
      switch (lifePoint) {
        case 1: color = Color.White; break;
        case 2: color = Color.Yellow; break;
        case 3: color = Color.Red; break;
        default:
          color = Color.Blue; break;
      }

      return new ColorAdapter(color);
    }

    public virtual IPowerImplementator Power { get; set; }

    public static IGraphicResource TextureByType(IContentManager contentManager, PowerUpFactory.ePowerUp type) {
      IGraphicResource resource;
      // bullet speed --> circle
      // speed --> cube
      // life --> star

      switch (type) {
        case PowerUpFactory.ePowerUp.Player_Speed:
        case PowerUpFactory.ePowerUp.Player_Slow:
        case PowerUpFactory.ePowerUp.Army_Speed:
        case PowerUpFactory.ePowerUp.Army_Slow:
          resource = contentManager.LoadTexture("cube"); break;
        
        case PowerUpFactory.ePowerUp.Army_Bullet_Speed:
        case PowerUpFactory.ePowerUp.Army_Bullet_Slow:
        case PowerUpFactory.ePowerUp.Player_Bullet_Speed:
        case PowerUpFactory.ePowerUp.Player_Bullet_Slow:
          resource = contentManager.LoadTexture("circle"); break;
        
        case PowerUpFactory.ePowerUp.Life:
          resource = contentManager.LoadTexture("star"); break;
        
        default:
          resource = contentManager.LoadTexture("ball");
          break;
      }

      return resource;
    }
  }
}
